package org.example.cgg.tools.word;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class WordTemplateUtil {

    /**
     * 通用替换方法，支持字符串和多段落List<String>
     *
     * @param doc  XWPFDocument对象
     * @param data Map<String,Object>，value为String或List<String>
     */
    public static void replaceAllPlaceholders(XWPFDocument doc, Map<String, Object> data) {
        // 替换页眉
        replaceHeader(doc, data);

        // 替换文档正文段落
        replaceParagraphs(doc, data);

        // 替换表格内段落
        replaceTables(doc, data);
    }

    public static void replaceHeader(XWPFDocument doc, Map<String, Object> data) {
        List<XWPFHeader> headerList = doc.getHeaderList();
        for (XWPFHeader xwpfHeader : headerList) {
            List<XWPFParagraph> paragraphs = xwpfHeader.getParagraphs();
            for (XWPFParagraph para : paragraphs) {
                replaceInParagraph(para, data);
            }
        }
    }

    public static void replaceParagraphs(XWPFDocument doc, Map<String, Object> data) {
        List<XWPFParagraph> paragraphs = new ArrayList<>(doc.getParagraphs());
        for (XWPFParagraph para : paragraphs) {
            replaceInParagraph(para, data);
        }
    }

    public static void replaceTables(XWPFDocument doc, Map<String, Object> data) {
        for (XWPFTable table : doc.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        replaceInParagraph(paragraph, data);
                    }
                }
            }
        }
    }

    /**
     * 替换段落中所有占位符，支持跨Run占位符，继承格式
     */
    public static void replaceInParagraph(XWPFParagraph paragraph, Map<String, Object> data) {

        log.debug("{}", paragraph.getText());

        String fullText = paragraph.getText();

        // 使用正则表达式匹配所有占位符，如 ${applicant}
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}");
        Matcher matcher = pattern.matcher(fullText);

        List<XWPFRun> runs = paragraph.getRuns();

        while (matcher.find()) {
            String placeholder = matcher.group(0); // 完整占位符，例如 ${applicant}
            String key = matcher.group(1);           // 占位符内的key，例如 applicant

            if (data.containsKey(key)) {
                Object valueObj = data.get(key);
                int[] runPos = findPlaceholderRunPosition(runs, placeholder);
                if (runPos != null) {
                    int startRun = runPos[0];
                    int endRun = runPos[1];

                    // 获取该Run的格式信息，用于复制
                    XWPFRun templateRun = runs.get(startRun);
                    String fontFamily = templateRun.getFontFamily();
                    int fontSize = templateRun.getFontSize();
                    boolean isBold = templateRun.isBold();
                    boolean isItalic = templateRun.isItalic();
                    String color = templateRun.getColor();

                    // 根据值类型进行替换
                    if (valueObj instanceof List) {
                        @SuppressWarnings("unchecked")
                        List<String> lines = (List<String>) valueObj;
                        // 先清除原有Run中的文本
                        clearRunsText(runs, startRun, endRun);
                        // 设置第一行
                        templateRun.setText(lines.get(0), 0);
                        setRunFormat(templateRun, fontFamily, fontSize, isBold, isItalic, color);

                        // 插入多行
                        XmlCursor cursor = paragraph.getCTP().newCursor();
                        cursor.toEndToken();
                        cursor.toNextToken(); // 移动到下一个Token，保证游标不指向段落内部或结尾标记
                        for (int i = 1; i < lines.size(); i++) {
                            XWPFParagraph newPara = paragraph.getDocument().insertNewParagraph(cursor);
                            XWPFRun run = newPara.createRun();
                            run.setText(lines.get(i));
                            setRunFormat(run, fontFamily, fontSize, isBold, isItalic, color);
                            // 拷贝缩进等格式（如果需要的话）
                            newPara.setIndentationFirstLine(paragraph.getIndentationFirstLine());
                            cursor = newPara.getCTP().newCursor();
                            cursor.toEndToken();
                            cursor.toNextToken();
                        }
                    } else {
                        String replacedText = valueObj == null ? "" : valueObj.toString();
                        // 只替换在占位符区域的文本
                        clearRunsText(runs, startRun, endRun);
                        templateRun.setText(replacedText, 0);
                        setRunFormat(templateRun, fontFamily, fontSize, isBold, isItalic, color);
                    }
                }
            }
        }
    }

    private static void setRunFormat(XWPFRun run, String fontFamily, int fontSize, boolean isBold, boolean isItalic, String color) {
        if (fontFamily != null) run.setFontFamily(fontFamily);
        if (fontSize > 0) run.setFontSize(fontSize);
        run.setBold(isBold);
        run.setItalic(isItalic);
        if (color != null) run.setColor(color);
    }

    private static void clearRunsText(List<XWPFRun> runs, int start, int end) {
        for (int i = start; i <= end; i++) {
            runs.get(i).setText("", 0);
        }
    }

    private static int[] findPlaceholderRunPosition(List<XWPFRun> runs, String placeholder) {
        StringBuilder sb = new StringBuilder();
        List<Integer> runStarts = new ArrayList<>();
        for (XWPFRun run : runs) {
            runStarts.add(sb.length());
            String text = run.getText(0);
            sb.append(text == null ? "" : text);
        }
        String fullText = sb.toString();

        int index = fullText.indexOf(placeholder);
        if (index == -1) return null;

        int startRun = -1, endRun = -1;
        for (int i = 0; i < runStarts.size(); i++) {
            int startIndex = runStarts.get(i);
            int endIndex = (i == runStarts.size() - 1) ? fullText.length() : runStarts.get(i + 1);
            if (startRun == -1 && index >= startIndex && index < endIndex) startRun = i;
            if (endRun == -1 && (index + placeholder.length() - 1) >= startIndex && (index + placeholder.length() - 1) < endIndex)
                endRun = i;
            if (startRun != -1 && endRun != -1) break;
        }
        if (startRun != -1 && endRun != -1) return new int[]{startRun, endRun};
        return null;
    }

    /**
     * 清空段落所有Run
     */
    public static void clearParagraph(XWPFParagraph paragraph) {
        int runCount = paragraph.getRuns().size();
        for (int i = runCount - 1; i >= 0; i--) {
            paragraph.removeRun(i);
        }
    }

    public static void replaceParagraph(XWPFParagraph paragraph, Map<String, Object> data) {
        List<XWPFRun> runs = paragraph.getRuns();
        System.out.println(runs);
        for (int i = 0; i < runs.size(); i++) {
            if ("${".equals(runs.get(i).getText(0)) && i + 2 < runs.size() && "}".equals(runs.get(i + 2).getText(0))) {
                runs.get(i).setText("", 0);
                runs.get(i + 1).setText((String) data.get(runs.get(i + 1).getText(0)), 0);
                runs.get(i + 2).setText("", 0);
                i += 2;
            }
        }
    }

    private static void copyParagraph(XWPFParagraph srcParagraph, XWPFParagraph destParagraph) {
        // 复制段落文本
        destParagraph.setStyle(srcParagraph.getStyle()); // 复制样式（如果需要）
        for (XWPFRun run : srcParagraph.getRuns()) {
            XWPFRun newRun = destParagraph.createRun(); // 创建新的run对象
            newRun.setText(run.getText(0), 0); // 复制文本内容
            newRun.setFontFamily(run.getFontFamily()); // 复制字体家族（如果需要）
            newRun.setFontSize(run.getFontSize()); // 复制字体大小（如果需要）
            newRun.setBold(run.isBold()); // 复制粗体样式（如果需要）
            newRun.setItalic(run.isItalic()); // 复制斜体样式（如果需要）
            newRun.setUnderline(run.getUnderline()); // 复制下划线样式（如果需要）
            // 可以根据需要复制更多的样式和属性...
        }
    }
}
